/*
 * Copyright (c) 2013, Ivan Babushkin.
 */
package asngen.codec;

import java.io.DataInputStream;
import java.io.IOException;
import java.lang.Long;

class IntegerDecoderRuntime {
    private DataInputStream dis;
    protected long leftBound;
    protected long rightBound;
    protected int size;

    private static final long MASK_1 = 0xffL;
    private static final long MASK_2 = 0xffffL;
    private static final long MASK_3 = 0xffffffL;
    private static final long MASK_4 = 0xffffffffL;
    private static final long MASK_5 = 0xffffffffffL;
    private static final long MASK_6 = 0xffffffffffffL;
    private static final long MASK_7 = 0xffffffffffffffL;
    private static final long MASK_8 = 0xffffffffffffffffL;

    public IntegerDecoderRuntime(DataInputStream dis, long l, long r) {
        leftBound = l;
        rightBound = r;
        this.dis = dis;
    }

    protected long twosComplement() throws IOException {
        switch (size) {
            case 1: dis.readByte();
            case 2:
                return dis.readShort();
            case 3:
                return (dis.readByte() << 16) | dis.readShort();
            case 4:
                return dis.readInt();
            case 5:
                return (dis.readByte() << 32) | dis.readInt();
            case 6:
                return (dis.readShort() << 32) | dis.readInt();
            case 7:
                return (dis.readByte() << 48) |
                        (dis.readShort() << 32) | dis.readInt();
            default:
                return dis.readLong();
        }
    }

    protected long positiveInt() throws IOException {
        switch (size) {
            case 1:
                return MASK_1 & dis.readByte();
            case 2:
                return MASK_2 & dis.readShort();
            case 3:
                return MASK_3 & ((dis.readByte() << 16) | dis.readShort());
            case 4:
                return MASK_4 & dis.readInt();
            case 5:
                return MASK_5 & ((dis.readByte() << 32) |
                        dis.readInt());
            case 6:
                return MASK_6 & ((dis.readShort() << 32) |
                        dis.readInt());
            case 7:
                return MASK_7 & ((dis.readByte() << 48) |
                        (dis.readShort() << 32) | dis.readInt());
            default:
                return dis.readLong();
        }
    }

    protected void fixedToMax() {
        if (leftBound >= 0) {
            if (rightBound < 0x100L) {
                size = 1;
            } else if (rightBound < 0x10000L) {
                size = 2;
            } else if (rightBound < 0x1000000L) {
                size = 4;
            } else {
                size = 8;
            }
        } else {
            if ((leftBound >= -128L) && (rightBound <= 127L)) {
                size = 1;
            } else if ((leftBound >= -32768L) && (rightBound <= 32767L)) {
                size = 2;
            } else if ((leftBound >= -2147483648L) && (rightBound <= 2147483647L)) {
                size = 4;
            } else {
                size = 8;
            }
        }
    }

    protected boolean boundedWithNegatives() {
        return leftBound < 0;
    }

    protected boolean boundedWithoutNegatives() {
        return leftBound >= 0;
    }
}
